﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System.Windows.Controls;
using System.Windows;
using DevExpress.AgDataGrid.Internal;
using DevExpress.AgDataGrid.Data;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Media;
using System.Windows.Markup;
using System.Reflection;
using System.Linq;
using System.Windows.Data;
using System.Globalization;
using System.IO;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using DevExpress.AgDataGrid;
using System.Collections.Specialized;
namespace DevExpress.AgDataGrid {
	public enum ImageSourceKind { Data, Uri };
	public interface IAgDataGridColumnOwner {
		void SortBy(AgDataGridColumn column, int sortIndex);
		void SortBy(AgDataGridColumn column, ColumnSortOrder sortOrder);
		void GroupBy(AgDataGridColumn column, int groupIndex);
		void Ungroup(AgDataGridColumn column, int newVisibleIndex);
		void ChangeSortOnClick(AgDataGridColumn column);
		int ColumnIndexOf(AgDataGridColumn column);
		void OnColumnWidthChanged(AgDataGridColumn column);
		void OnColumnVisibilityChanged(AgDataGridColumn column);
		bool IsInsideHeaderPanel(double x);
		double ColumnIndent(AgDataGridColumn column);
		double GetColumnHeaderWidth(AgDataGridColumn column);
		void ChangeColumnWidthOnResize(AgDataGridColumn column, double newWidth);
		void OnColumnCellStyleChanged(AgDataGridColumn column);
		void OnColumnCellDisplayTemplateChanged(AgDataGridColumn column);
		Canvas Surface { get; }
		List<SummaryItemType> GetTotalList(string fieldName);
		void SetTotalList(string FieldName, List<SummaryItemType> value);
		List<SummaryItemType> GetUnavailableSummaryList(AgDataGridColumn column);
		bool ColumnsAutoWidth { get; set; }
		Style GetColumnHeaderStyle(AgDataGridColumnHeaderState state);
		FrameworkElement DragArrows { get; }
		bool IsSortingAllowed(AgDataGridColumn column);
		void ActivateEditor(AgDataGridColumn column, int rowHandle, object value);
		bool IsEditorShown { get; }
		bool AllowColumnSorting { get; }
		bool AllowColumnGrouping { get; }
		bool AllowColumnResizing { get; }
		bool AllowColumnMoving { get; }
		bool AllowEditing { get; }
		void EndEdit();
		bool CanStartEdit { get; }
		Style TotalCellStyle { get; }
	}
	internal class NullAgDataGridColumnOwner : IAgDataGridColumnOwner {
		public void SortBy(AgDataGridColumn column, int sortIndex) { column.SetSortIndex(sortIndex); }
		public void SortBy(AgDataGridColumn column, ColumnSortOrder sortOrder) { column.SetSortOrder(sortOrder); }
		public void GroupBy(AgDataGridColumn column, int groupIndex) {
			column.SetGroupIndex(groupIndex);
			column.SetSortOrder(ColumnSortOrder.Ascending);
		}
		public void Ungroup(AgDataGridColumn column, int newIndex) {
			column.SetGroupIndex(-1);
			column.VisibleIndex = newIndex;
		}
		public void ChangeSortOnClick(AgDataGridColumn column) { }
		public int ColumnIndexOf(AgDataGridColumn column) { return -1; }
		public void OnColumnWidthChanged(AgDataGridColumn column) { }
		public void OnColumnVisibilityChanged(AgDataGridColumn column) { }
		public bool IsInsideHeaderPanel(double x) { return false; }
		public double GetColumnHeaderWidth(AgDataGridColumn column) { return column.ActualWidth; }
		public double ColumnIndent(AgDataGridColumn column) { return .0; }
		public void ChangeColumnWidthOnResize(AgDataGridColumn column, double newWidth) { }
		public void OnColumnCellStyleChanged(AgDataGridColumn column) { }
		public void OnColumnCellDisplayTemplateChanged(AgDataGridColumn column) { }
		public Canvas Surface { get { return null; } }
		public List<SummaryItemType> GetTotalList(string fieldName) { return null; }
		public void SetTotalList(string FieldName, List<SummaryItemType> value) { }
		public List<SummaryItemType> GetUnavailableSummaryList(AgDataGridColumn column) { return null; }
		public bool ColumnsAutoWidth { get; set; }
		public Style GetColumnHeaderStyle(AgDataGridColumnHeaderState state) { return null; }
		public FrameworkElement DragArrows { get { return null; } }
		public bool IsSortingAllowed(AgDataGridColumn column) { return true; }
		public void ActivateEditor(AgDataGridColumn column, int rowHandle, object value) { }
		public bool AllowColumnSorting { get { return true; } }
		public bool AllowColumnGrouping { get { return true; } }
		public bool AllowColumnResizing { get { return true; } }
		public bool AllowColumnMoving { get { return true; } }
		public bool AllowEditing { get { return true; } }
		public bool IsEditorShown { get { return false; } }
		public void EndEdit() { }
		public bool CanStartEdit { get { return false; } }
		public Style TotalCellStyle { get { return null; } }
	}
	public abstract class AgDataGridOwnedObject {
		protected internal abstract void SetOwner(object value);
	}
	public class AgDataGridColumn : AgDataGridOwnedObject, IResizableObject, IColumnAutoWidth, IAgDataGridTotalCellOwner {
		const string DefaultTemplateNamespaces =
			@"xmlns=""http://schemas.microsoft.com/client/2007"" 
   		      xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" 
			  xmlns:local=""clr-namespace:DevExpress.AgDataGrid;assembly=DevExpress.AgDataGrid.v8.2"">";
		AgDataGridColumnHeader headerControl;
		AgDataGridTotalCell totalCellControl;
		DataTemplate cellEditingTemplate;
		DataTemplate cellDisplayTemplate;
		AgDataGridColumnGroupedHeader groupedHeaderControl;
		double width = 0;
		string fieldName;
		bool visible;
		int visibleIndex;
		double minColumnWidth;
		ColumnSortOrder sortOrder;
		int sortIndex;
		int groupIndex;
		IAgDataGridColumnOwner owner;
		Style cellStyle;
		Style headerStyle;
		bool fixedWidth;
		Style cellDisplayElementStyle;
		object headerContent;
		public AgDataGridColumn() {
			this.minColumnWidth = -1;
			this.visibleIndex = -1;
			this.visible = true;
			this.sortOrder = ColumnSortOrder.None;
			this.sortIndex = -1;
			this.groupIndex = -1;
		}
		public event TemplateColumnValueEditingEventHandler EndEditing;
		public event TemplateColumnValueEditingEventHandler BeginEditing;
		public event PrepareCellDisplayElementEventHandler PrepareCellDisplayElement;
		public DataTemplate CellEditingTemplate {
			get { return this.cellEditingTemplate; }
			set {
				if (value == this.cellEditingTemplate) return;
				this.cellEditingTemplate = value;
				OnCellEditingTemplateChanged();
			}
		}
		public DataTemplate CellDisplayTemplate {
			get { return this.cellDisplayTemplate; }
			set {
				if (value == this.cellDisplayTemplate) return;
				this.cellDisplayTemplate = value;
				OnCellDisplayTemplateChanged();
			}
		}
		public DataTemplate GetCellEditingTemplate() {
			return CellEditingTemplate ?? GetCellDefaultEditingTemplate();
		}
		public DataTemplate GetCellDisplayTemplate() {
			return CellDisplayTemplate ?? GetCellDefaultDisplayTemplate(); ;
		}
		protected virtual DataTemplate GetCellDefaultDisplayTemplate() {
			return XamlReader.Load(GetCellDefaultDisplayTemplateText()) as DataTemplate;
		}
		protected virtual DataTemplate GetCellDefaultEditingTemplate() {
			string editControlText = GetCellDefaultEditControlTemplateText();
			if (string.IsNullOrEmpty(editControlText)) return null;
			return XamlReader.Load(string.Format(GetCellDefaultTemplateFormatText(), editControlText)) as DataTemplate;
		}
		protected string GetCellDefaultDisplayTemplateText() {
			return string.Format(GetCellDefaultTemplateFormatText(), GetCellDefaultDisplayControlTemplateText());
		}
		protected virtual string GetCellDefaultTemplateFormatText() {
			return "<DataTemplate " + DefaultTemplateNamespaces + " {0} </DataTemplate>";
		}
		protected virtual string GetCellDefaultDisplayControlTemplateText() {
			return string.Format("<TextBlock Text='{{Binding CellValue}}' TextAlignment='{0}' TextWrapping='{1}'/>",
				GetHorizontalContentAlignment().ToString(), GetTextWrapping() == TextWrapping.Wrap ? "Wrap" : "NoWrap");
		}
		protected virtual string GetCellDefaultEditControlTemplateText() { return string.Empty; }
		protected virtual void OnCellEditingTemplateChanged() {
		}
		protected virtual void OnCellDisplayTemplateChanged() {
			Owner.OnColumnCellDisplayTemplateChanged(this);
		}
		protected internal virtual object GetEditorValue(FrameworkElement editor, out bool hasValue) {
			return RaiseEndEditingEvents(editor, out hasValue);
		}
		protected object RaiseEndEditingEvents(FrameworkElement editor, out bool hasValue) {
			hasValue = false;
			if (EndEditing == null) return null;
			EditingEventArgs args = new EditingEventArgs(editor);
			EndEditing(this, args);
			hasValue = true;
			return args.Value;
		}
		protected void RaiseBeginEditingEvents(FrameworkElement editor, object value) {
			if (BeginEditing == null) return;
			BeginEditing(this, new EditingEventArgs(editor, value));
		}
		protected internal virtual void SetEditorValue(FrameworkElement editor, object value) {
			RaiseBeginEditingEvents(editor, value);
		}
		protected internal virtual void BeforeHidingEditor(FrameworkElement editor) { }
		protected internal virtual void OnPrepareCellDisplayElement(AgDataGridCell cell, FrameworkElement displayElement) {
			new FontLayoutHelper(cell).SetFont(displayElement);
			StyleLoader.ApplyStyle(displayElement, CellDisplayElementStyle);
			RaisePrepareCellDisplayElement(cell, displayElement);
		}
		void RaisePrepareCellDisplayElement(AgDataGridCell cell, FrameworkElement displayElement) {
			if (PrepareCellDisplayElement != null)
				PrepareCellDisplayElement(this, new PrepareCellDisplayElementEventArgs(cell.Value, displayElement));
		}
		protected internal virtual void PrepareEditor(FrameworkElement editor, AgDataGridCell cell) {
			StyleLoader.ApplyStyle(editor, CellEditorStyle);
		}
		public ColumnSortOrder SortOrder {
			get { return sortOrder; }
			set {
				if (SortOrder == value) return;
				if (!Owner.IsSortingAllowed(this)) return;
				if (GroupIndex >= 0 && value == ColumnSortOrder.None) return;
				Owner.SortBy(this, value);
				OnSortGroupPropertiesChanged();
			}
		}
		object headerToolTip;
		public object HeaderToolTip {
			get {
				return headerToolTip;
			}
			set {
				if (headerToolTip == value) return;
				headerToolTip = value;
				OnHeaderToolTipChanged();
			}
		}
		protected virtual void OnHeaderToolTipChanged() {
			if (HeaderControl != null) {
				ToolTipService.SetToolTip(HeaderControl, HeaderToolTip);
			}
		}
		DefaultBoolean allowResizing;
		public DefaultBoolean AllowSorting { get; set; }
		public DefaultBoolean AllowGrouping { get; set; }
		public DefaultBoolean AllowMoving { get; set; }
		public DefaultBoolean AllowResizing {
			get { return allowResizing; }
			set {
				if (AllowResizing == value) return;
				allowResizing = value;
				UpdateAllowResizing();
			}
		}
		public DefaultBoolean AllowEditing { get; set; }
		protected bool CanUserSort {
			get {
				if (!Owner.IsSortingAllowed(this)) return false;
				return AllowSorting.HasValue() ? AllowSorting.Value() : Owner.AllowColumnSorting;
			}
		}
		protected internal bool CanUserGroup {
			get {
				if (!CanUserSort) return false;
				return AllowGrouping.HasValue() ? AllowGrouping.Value() : Owner.AllowColumnGrouping;
			}
		}
		protected internal bool CanUserMoving { get { return AllowMoving.HasValue() ? AllowMoving.Value() : Owner.AllowColumnMoving; } }
		protected internal bool CanUserResizing { get { return AllowResizing.HasValue() ? AllowResizing.Value() : Owner.AllowColumnResizing; } }
		protected internal bool CanUserEditing { get { return AllowEditing.HasValue() ? AllowEditing.Value() : Owner.AllowEditing; } }
		protected internal void UpdateAllowResizing() {
			if (HeaderControl != null)
				HeaderControl.UpdateAllowResizing();
		}
		public bool FixedWidth {
			get { return fixedWidth; }
			set {
				if (value == fixedWidth) return;
				fixedWidth = value;
				OnWidthChanged();
			}
		}
		public int SortIndex {
			get { return sortIndex; }
			set {
				if (SortIndex == value) return;
				Owner.SortBy(this, value);
				OnSortGroupPropertiesChanged();
			}
		}
		public int GroupIndex {
			get { return groupIndex; }
			set {
				if (GroupIndex == value) return;
				if (!Owner.IsSortingAllowed(this)) return;
				Owner.GroupBy(this, value);
				OnSortGroupPropertiesChanged();
			}
		}
		protected internal void ReverseSort() {
			SortOrder = SortOrder == ColumnSortOrder.Ascending ? ColumnSortOrder.Descending : ColumnSortOrder.Ascending;
		}
		protected internal void ChangeSortOnClick(bool isShift, bool isCtrl) {
			if (!CanUserSort) return;
			if (isShift) {
				ReverseSort();
				return;
			}
			if (isCtrl) {
				SortOrder = ColumnSortOrder.None;
				return;
			}
			Owner.ChangeSortOnClick(this);
		}
		protected internal void SetSortOrder(ColumnSortOrder value) {
			this.sortOrder = value;
			OnSortGroupPropertiesChanged();
		}
		protected internal void SetSortIndex(int value) {
			this.sortIndex = value;
		}
		protected internal void SetGroupIndex(int value) {
			this.groupIndex = value;
		}
		protected virtual void OnSortGroupPropertiesChanged() {
			HeaderControl.SortOrder = SortOrder;
			GroupedHeaderControl.SortOrder = SortOrder;
		}
		public double MaxColumnWidth { get; set; }
		public double MinColumnWidth {
			get { return Owner.ColumnIndent(this) + (minColumnWidth >= 0 ? minColumnWidth : AgDataGrid.DefaultColumnMinWidth); }
			set { minColumnWidth = value > 0 ? value : 0; }
		}
		public string FieldName {
			get { return fieldName; }
			set {
				if (fieldName == value) return;
				fieldName = value;
				OnNameHeaderContentChanged();
			}
		}
		public bool Visible {
			get { return visible; }
			set {
				if (Visible == value) return;
				visible = value;
				if (value) {
					this.visibleIndex = OldVisibleIndex;
				}
				OnVisibilityChanged();
			}
		}
		public Style HeaderStyle {
			get { return headerStyle; }
			set {
				if (value == headerStyle) return;
				headerStyle = value;
				if (HeaderControl.Style == null && value != null)
					HeaderControl.Style = value;
			}
		}
		protected internal Canvas Surface { get { return Owner.Surface; } }
		protected internal int VisibleIndexCore { get; set; }
		protected internal int OldVisibleIndex { get { return Owner.ColumnIndexOf(this); } }
		public int VisibleIndex {
			get {
				if (!Visible) return -1;
				return visibleIndex >= 0 ? visibleIndex : VisibleIndexCore;
			}
			set {
				if (value < 0) {
					Visible = false;
					return;
				}
				this.visible = true;
				this.visibleIndex = value;
				OnVisibilityChanged();
			}
		}
		protected internal void SetVisibilityProperties(bool visible, int visibleIndex) {
			this.visible = visible;
			this.visibleIndex = visibleIndex;
		}
		public double Width {
			get {
				if (width == 0) {
					return Owner.ColumnIndent(this) + (AgDataGrid.DefaultColumnWidth < MinColumnWidth ? MinColumnWidth : AgDataGrid.DefaultColumnWidth);
				}
				return (Owner.ColumnIndent(this) + width) > MinColumnWidth || Owner.ColumnsAutoWidth ? Owner.ColumnIndent(this) + width : MinColumnWidth;
			}
			set {
				if (Width == value) return;
				value -= Owner.ColumnIndent(this);
				width = value;
				OnWidthChanged();
			}
		}
		public Style CellStyle {
			get { return this.cellStyle; }
			set {
				if (value == this.cellStyle) return;
				this.cellStyle = value;
				OnCellStyleChanged();
			}
		}
		protected virtual void OnCellStyleChanged() {
			Owner.OnColumnCellStyleChanged(this);
		}
		public object HeaderContent {
			get { return headerContent; }
			set {
				if (HeaderContent == value) return;
				headerContent = value;
				OnNameHeaderContentChanged();
			}
		}
		protected virtual void OnWidthChanged() { Owner.OnColumnWidthChanged(this); }
		protected virtual void OnVisibilityChanged() { Owner.OnColumnVisibilityChanged(this); }
		protected virtual void OnNameHeaderContentChanged() {
			GroupedHeaderControl.Content = GetHeaderContent();
			HeaderControl.Content = GetHeaderContent();
		}
		protected virtual object GetHeaderContent() {
			return HeaderContent != null ? HeaderContent : FieldNameToCaption();
		}
		string FieldNameToCaption() {
			string field, res;
			field = res = FieldName;
			int replaced = 0;
			for (int i = 1; i < field.Length - 1; i++) {
				if (char.IsUpper(field[i]) &&
					!char.IsUpper(field[i + 1]) && !char.IsWhiteSpace(field[i - 1]) && !char.IsWhiteSpace(field[i + 1])) {
					res = res.Insert(i + replaced++, " ");
				}
			}
			return res;
		}
		protected internal AgDataGridColumnGroupedHeader GroupedHeaderControl {
			get { return groupedHeaderControl ?? (groupedHeaderControl = CreateGroupedColumnHeader()); }
		}
		protected internal AgDataGridColumnHeader HeaderControl {
			get { return headerControl ?? (headerControl = CreateColumnHeader()); }
		}
		protected internal AgDataGridTotalCell TotalCellControl {
			get { return totalCellControl ?? (totalCellControl = CreateTotalCellControl()); }
		}
		protected virtual AgDataGridTotalCell CreateTotalCellControl() {
			AgDataGridTotalCell result = new AgDataGridTotalCell(this);
			if (result.Style == null && Owner.TotalCellStyle != null)
				result.Style = Owner.TotalCellStyle;
			return result;
		}
		protected virtual AgDataGridColumnHeader CreateColumnHeader() { return new AgDataGridColumnHeader(this); }
		protected virtual AgDataGridColumnGroupedHeader CreateGroupedColumnHeader() { return new AgDataGridColumnGroupedHeader(this); }
		protected internal virtual List<SummaryItemType> UnavailableList {
			get {
				return Owner.GetUnavailableSummaryList(this);
			}
		}
		protected internal double PerformHeaderLayout(double left, double height) {
			HeaderControl.Width = Width;
			HeaderControl.Height = height;
			HeaderControl.SetValue(Canvas.LeftProperty, left);
			return Width;
		}
		protected virtual TextAlignment GetHorizontalContentAlignment() { return TextAlignment.Left; }
		protected virtual TextWrapping GetTextWrapping() { return TextWrapping.NoWrap; }
		protected internal IAgDataGridColumnOwner Owner {
			get { return owner != null ? owner : NullOwner; }
			set { owner = value; }
		}
		protected internal override void SetOwner(object value) { Owner = value as IAgDataGridColumnOwner; }
		static IAgDataGridColumnOwner nullOwner = null;
		static protected internal IAgDataGridColumnOwner NullOwner {
			get { return nullOwner ?? (nullOwner = new NullAgDataGridColumnOwner()); }
		}
		public Style CellDisplayElementStyle {
			get { return this.cellDisplayElementStyle; }
			set {
				if (value == this.cellDisplayElementStyle) return;
				this.cellDisplayElementStyle = value;
				OnCellDisplayElementStyleChanged();
			}
		}
		void OnCellDisplayElementStyleChanged() {
			Owner.OnColumnCellDisplayTemplateChanged(this);
		}
		public Style CellEditorStyle { get; set; }
		#region IResizableObject Members
		double IResizableObject.Size { get { return ActualWidth; } set { SetWidthOnResizing(value); } }
		double IResizableObject.MinSize { get { return MinColumnWidth; } }
		double IResizableObject.MaxSize { get { return MaxColumnWidth; } }
		#endregion
		#region IColumnAutoWidth Members
		double actualWidth = -1;
		internal double AutoWidthActualWidth { get { return actualWidth; } }
		double IColumnAutoWidth.Width { get { return this.Width; } }
		public int ActualWidth {
			get { return (int)(!Owner.ColumnsAutoWidth ? Width : Math.Max(actualWidth, 0)); }
			protected internal set { actualWidth = value; }
		}
		int IColumnAutoWidth.ActualWidth {
			get { return (int)actualWidth; }
			set { this.actualWidth = value; }
		}
		int IColumnAutoWidth.MinWidth { get { return (int)this.MinColumnWidth; } }
		internal void SetWidthOnResizing(double value) {
			Owner.ChangeColumnWidthOnResize(this, value);
		}
		bool IColumnAutoWidth.FixedWidth { get { return FixedWidth; } }
		#endregion
		#region IAgDataGridTotalCellOwner Members
		void IAgDataGridTotalCellOwner.TotalCellStyleChanged() {
			totalCellControl = null;
		}
		Canvas IAgDataGridTotalCellOwner.Surface { get { return Surface; } }
		List<SummaryItemType> IAgDataGridTotalCellOwner.SummaryList {
			get { return Owner.GetTotalList(FieldName); }
			set { Owner.SetTotalList(FieldName, value); }
		}
		List<SummaryItemType> IAgDataGridTotalCellOwner.UnavailableList {
			get {
				return UnavailableList;
			}
		}
		#endregion
		protected internal virtual void PrepareCell(AgDataGridCell cell) {
			cell.TextWrapping = GetTextWrapping();
		}
		public override string ToString() {
			if (GetHeaderContent() != null) return GetHeaderContent().ToString();
			return base.ToString();
		}
		protected internal virtual bool IsEditorFocused(FrameworkElement editor) {
			return FocusManager.GetFocusedElement() == editor;
		}
	}
	public class AgDataGridTextColumn : AgDataGridColumn {
		TextAlignment horizontalContentAlignment;
		TextWrapping textWrapping;
		public TextAlignment HorizontalContentAlignment {
			get { return this.horizontalContentAlignment; }
			set {
				if (value == this.horizontalContentAlignment) return;
				this.horizontalContentAlignment = value;
				HorizontalAlignmentChanged();
			}
		}
		public TextWrapping TextWrapping {
			get {
				return textWrapping;
			}
			set {
				if (textWrapping == value) return;
				textWrapping = value;
				OnTextWrappingChanged();
			}
		}
		public AgDataGridTextColumn() {
			this.textWrapping = TextWrapping.NoWrap;
			this.horizontalContentAlignment = TextAlignment.Left;
		}
		protected virtual void HorizontalAlignmentChanged() {
			Owner.OnColumnCellDisplayTemplateChanged(this);
		}
		protected virtual void OnTextWrappingChanged() {
			Owner.OnColumnCellDisplayTemplateChanged(this);
		}
		protected override string GetCellDefaultEditControlTemplateText() {
			return string.Format("<local:AgDataGridTextBox TextAlignment='{0}'/>", GetHorizontalContentAlignment().ToString());
		}
		protected internal override object GetEditorValue(FrameworkElement editor, out bool hasValue) {
			hasValue = true;
			return (editor as AgDataGridTextBox).Text;
		}
		protected internal override void SetEditorValue(FrameworkElement editor, object value) {
			AgDataGridTextBox ed = (AgDataGridTextBox)editor;
			ed.Text = value != null ? value.ToString() : string.Empty;
			ed.Select(0, ed.Text.Length);
		}
		protected internal override void PrepareEditor(FrameworkElement editor, AgDataGridCell cell) {
			AgDataGridTextBox tb = (AgDataGridTextBox)editor;
			if (tb != null && cell != null) {
				new FontLayoutHelper(cell).SetFont(tb);
				tb.HorizontalAlignment = HorizontalAlignment.Stretch;
			}
			base.PrepareEditor(editor, cell);
		}
		protected override TextAlignment GetHorizontalContentAlignment() { return HorizontalContentAlignment; }
		protected override TextWrapping GetTextWrapping() { return TextWrapping; }
	}
	public class AgDataGridDateColumnContentConverter : IValueConverter {
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
			if (value is DateTime) {
				return ((DateTime)value).ToShortDateString();
			} else {
				return value;
			}
		}
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
			throw new NotImplementedException();
		}
	}
	public class AgDataGridTextColumnContentConverter : IValueConverter {
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
			if (value is double) {
				return ((double)value).ToString();
			} else
				if (value is decimal) {
					return string.Format("{0:c}", value);
				} else
					return value;
		}
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
			throw new NotImplementedException();
		}
	}
	public class AgDataGridDateColumn : AgDataGridColumn {
		public AgDataGridDateColumn() { }
		protected override string GetCellDefaultEditControlTemplateText() {
			return "<local:AgDataGridDatePicker />";
		}
		protected internal override object GetEditorValue(FrameworkElement editor, out bool hasValue) {
			hasValue = true;
			return (editor as AgDataGridDatePicker).Text;
		}
		protected internal override void SetEditorValue(FrameworkElement editor, object value) {
			AgDataGridDatePicker ed = editor as AgDataGridDatePicker;
			ed.SelectedDate = (DateTime)value;
		}
		protected internal override void PrepareEditor(FrameworkElement editor, AgDataGridCell cell) {
			AgDataGridDatePicker tb = (AgDataGridDatePicker)editor;
			if (tb != null && cell != null) {
				new FontLayoutHelper(cell).SetFont(tb.TextEditor);
				tb.Padding = cell.Margin;
			}
			base.PrepareEditor(editor, cell);
		}
		protected internal override bool IsEditorFocused(FrameworkElement editor) {
			FrameworkElement elem = FocusManager.GetFocusedElement() as FrameworkElement;
			if (elem is System.Windows.Controls.Calendar) return true;
			if (VisualTreeHelper.GetParent(elem) == null) return true;
			if (FindChild(Owner as DependencyObject, elem)) return true;
			return false;
		}
		bool FindChild(DependencyObject par, object elem) {
			if (par == null || elem == null) return false;
			for (int i = 0; i < VisualTreeHelper.GetChildrenCount(par); i++) {
				DependencyObject e = VisualTreeHelper.GetChild(par, i);
				if (e == elem) return true;
				else if (FindChild(e, elem)) return true;
			}
			return false;
		}
		protected internal override void OnPrepareCellDisplayElement(AgDataGridCell cell, FrameworkElement displayElement) {
			if (cell.Value.CellValue is DateTime)
				((TextBlock)displayElement).Text = ((DateTime)cell.Value.CellValue).ToShortDateString();
			base.OnPrepareCellDisplayElement(cell, displayElement);
		}
		protected internal override void BeforeHidingEditor(FrameworkElement editor) {
			base.BeforeHidingEditor(editor);
			(editor as DatePicker).IsDropDownOpen = false;
		}
	}
	public class AgDataGridCheckColumn : AgDataGridColumn {
		bool isThreeState;
		public AgDataGridCheckColumn() { }
		protected override string GetCellDefaultDisplayControlTemplateText() {
			return string.Format("<CheckBox IsThreeState='{0}' IsChecked='{{Binding CellValue}}' IsTabStop='False'/>", IsThreeState);
		}
		protected override string GetCellDefaultEditControlTemplateText() {
			return string.Format("<CheckBox IsThreeState='{0}' IsChecked='{{Binding CellValue}}'/>", IsThreeState);
		}
		public bool IsThreeState {
			get { return isThreeState; }
			set {
				if (value == IsThreeState) return;
				isThreeState = value;
				OnThreeStateChanged();
			}
		}
		void OnThreeStateChanged() {
			Owner.OnColumnCellDisplayTemplateChanged(this);
		}
		protected internal override object GetEditorValue(FrameworkElement editor, out bool hasValue) {
			hasValue = true;
			return ((ToggleButton)editor).IsChecked;
		}
		protected internal override void SetEditorValue(FrameworkElement editor, object value) {
			if (editor != null)
				((ToggleButton)editor).IsChecked = (bool?)value;
		}
		protected internal override void OnPrepareCellDisplayElement(AgDataGridCell cell, FrameworkElement displayElement) {
			((ToggleButton)displayElement).Click -= OnCheck_Click;
			((ToggleButton)displayElement).Click += OnCheck_Click;
			if (((ToggleButton)displayElement).Style == null)
				((ToggleButton)displayElement).Style = dxElementStyles.GetStyle("CheckBoxStyle");
			((ToggleButton)displayElement).HorizontalAlignment = HorizontalAlignment.Center;
			base.OnPrepareCellDisplayElement(cell, displayElement);
		}
		protected virtual void OnCheck_Click(object sender, RoutedEventArgs e) {
			AgDataGridRow row = FindRow(sender) as AgDataGridRow;
			if (row == null) return;
			if (!((ToggleButton)sender).IsTabStop)
				Owner.ActivateEditor(this, ((AgDataGridRow)FindRow(sender)).Handle, ((ToggleButton)sender).IsChecked);
			if (!Owner.CanStartEdit)
				((ToggleButton)sender).IsChecked = !((ToggleButton)sender).IsChecked;
		}
		private object FindRow(object o) {
			if (o == null) return null;
			if (o is AgDataGridRow) return o;
			return FindRow(VisualTreeHelper.GetParent(o as DependencyObject));
		}
		protected internal override void PrepareEditor(FrameworkElement editor, AgDataGridCell cell) {
			((ToggleButton)editor).Style = dxElementStyles.GetStyle("CheckBoxStyle");
			((ToggleButton)editor).HorizontalAlignment = HorizontalAlignment.Center;
			base.PrepareEditor(editor, cell);
		}
	}
	public class AgDataGridImageColumnContentConverter : IValueConverter {
		public ImageSourceKind SourceKind { get; set; }
		public AgDataGridImageColumnContentConverter() { }
		public AgDataGridImageColumnContentConverter(ImageSourceKind sourceKind) {
			SourceKind = sourceKind;
		}
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
			if (SourceKind == ImageSourceKind.Data && value is byte[]) {
				BitmapImage bi = new BitmapImage();
				bi.SetSource(new MemoryStream((byte[])value));
				return bi;
			} else {
				if (SourceKind == ImageSourceKind.Uri && value is string) {
					return new BitmapImage(new Uri(value as string));
				} else
					return null;
			}
		}
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
			throw new NotImplementedException();
		}
	}
	public class AgDataGridImageColumn : AgDataGridColumn {
		ImageSourceKind sourceKind;
		public ImageSourceKind SourceKind {
			get { return this.sourceKind; }
			set {
				if (value == this.sourceKind) return;
				this.sourceKind = value;
				SourceKindChanged();
			}
		}
		public AgDataGridImageColumn() {
			sourceKind = ImageSourceKind.Data;
		}
		protected override string GetCellDefaultDisplayControlTemplateText() {
			return "<Image/>";
		}
		protected virtual void SourceKindChanged() {
			Owner.OnColumnCellDisplayTemplateChanged(this);
		}
		protected internal override void OnPrepareCellDisplayElement(AgDataGridCell cell, FrameworkElement displayElement) {
			if (CellDisplayTemplate == null) {
				((Image)displayElement).SetBinding(Image.SourceProperty, new Binding("CellValue") { Converter = new AgDataGridImageColumnContentConverter(SourceKind) });
			}
			base.OnPrepareCellDisplayElement(cell, displayElement);
		}
	}
	public delegate void AgDataGridObservableCollectionBeforeCollectionChangedEventHandler(object sender, AgDataGridObservableCollectionBeforeCollectionChangedEventArgs e);
	public class AgDataGridObservableCollectionBeforeCollectionChangedEventArgs : EventArgs {
		public AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction action) : this(action, -1, null, null) { }
		public AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction action, object item, int insertIndex) :
			this(action, insertIndex, item, null) { }
		public AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction action, object item, object newItem) :
			this(action, -1, item, newItem) { }
		AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction action, int insertIndex, object item, object newItem) {
			Action = action;
			InsertIndex = insertIndex;
			Item = item;
			NewItem = newItem;
		}
		public NotifyCollectionChangedAction Action { get; private set; }
		public int InsertIndex { get; private set; }
		public object Item { get; private set; }
		public object NewItem { get; private set; }
	}
	public class AgDataGridObservableCollection<T> : ObservableCollection<T> {
		public AgDataGridObservableCollection() { }
		protected bool IsBusy { get; set; }
		public event AgDataGridObservableCollectionBeforeCollectionChangedEventHandler BeforeCollectionChanged;
		protected virtual void CheckReentrancy() {
			if (IsBusy)
				throw new InvalidOperationException();
		}
		protected override void ClearItems() {
			CheckReentrancy();
			if (Count > 0)
				RaiseBefoceCollectionChanged(new AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
			base.ClearItems();
		}
		protected override void InsertItem(int index, T item) {
			CheckReentrancy();
			RaiseBefoceCollectionChanged(new AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
			base.InsertItem(index, item);
		}
		protected virtual void RaiseBefoceCollectionChanged(AgDataGridObservableCollectionBeforeCollectionChangedEventArgs e) {
			if (BeforeCollectionChanged != null) {
				IsBusy = true;
				try {
					BeforeCollectionChanged(this, e);
				} finally {
					IsBusy = false;
				}
			}
		}
		protected override void RemoveItem(int index) {
			CheckReentrancy();
			RaiseBefoceCollectionChanged(new AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, this[index], -1));
			base.RemoveItem(index);
		}
		protected override void SetItem(int index, T item) {
			this.CheckReentrancy();
			RaiseBefoceCollectionChanged(new AgDataGridObservableCollectionBeforeCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, this[index], item));
			base.SetItem(index, item);
		}
	}
	public class AgDataGridColumnCollection : AgDataGridObservableCollection<AgDataGridColumn> {
		public AgDataGridColumnCollection() {
		}
		public AgDataGridColumn this[string name] {
			get {
				foreach (AgDataGridColumn column in this) {
					if (column.FieldName == name) return column;
				}
				return null;
			}
		}
   }
}
